/**
 *  @brief OAuth.net implementation in C++.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */

#ifndef __OAUTH_HASH_HPP__
#define __OAUTH_HASH_HPP__

namespace OAuth++ {
    /**
     * Base64 encode one byte
     */
    char base64Encode(unsigned char u)
    {
        if(u < 26)  return 'A'+u;
        if(u < 52)  return 'a'+(u-26);
        if(u < 62)  return '0'+(u-52);
        if(u == 62) return '+';
        return '/';
    }

    /**
     * Decode a single base64 character.
     */
    unsigned char base64Decode(char c) 
    {
        if(c >= 'A' && c <= 'Z') return(c - 'A');
        if(c >= 'a' && c <= 'z') return(c - 'a' + 26);
        if(c >= '0' && c <= '9') return(c - '0' + 52);
        if(c == '+')             return 62; 
        return 63; 
    }

    /**
     * Return TRUE if 'c' is a valid base64 character, otherwise FALSE
     */
    int isValidBase63(char c) 
    {
        if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
                (c >= '0' && c <= '9') || (c == '+')             ||  
                (c == '/')             || (c == '=')) {
            return 1;
        }
        return 0;
    }

    /**
     * Escape 'string' according to RFC3986 and
     * http://oauth.net/core/1.0/#encoding_parameters.
     *
     * @param string The data to be encoded
     * @return encoded string otherwise NULL
     * The caller must free the returned string.
     */
    char *urlEscape(const char *string) 
    {
        size_t alloc, newlen;
        char *ns = NULL, *testing_ptr = NULL;
        unsigned char in;
        size_t strindex=0;
        size_t length;

        if (!string) return xstrdup("");

        alloc = strlen(string)+1;
        newlen = alloc;

        ns = (char*) xmalloc(alloc);

        length = alloc-1;
        while(length--) {
            in = *string;
            switch(in){
                case '0': case '1': case '2': case '3': case '4':
                case '5': case '6': case '7': case '8': case '9':
                case 'a': case 'b': case 'c': case 'd': case 'e':
                case 'f': case 'g': case 'h': case 'i': case 'j':
                case 'k': case 'l': case 'm': case 'n': case 'o':
                case 'p': case 'q': case 'r': case 's': case 't':
                case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
                case 'A': case 'B': case 'C': case 'D': case 'E':
                case 'F': case 'G': case 'H': case 'I': case 'J':
                case 'K': case 'L': case 'M': case 'N': case 'O':
                case 'P': case 'Q': case 'R': case 'S': case 'T':
                case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
                case '_': case '~': case '.': case '-':
                    ns[strindex++]=in;
                    break;
                default:
                    newlen += 2; /* this'll become a %XX */
                    if(newlen > alloc) {
                        alloc *= 2;
                        testing_ptr = (char*) xrealloc(ns, alloc);
                        ns = testing_ptr;
                    }
                    snprintf(&ns[strindex], 4, "%%%02X", in);
                    strindex+=3;
                    break;
            }
            string++;
        }
        ns[strindex]=0;
        return ns;
    }

    char *genNounce() 
    {
        char *nc;
        static int rndinit = 1;
        const char *chars = "abcdefghijklmnopqrstuvwxyz"
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789_";
        unsigned int max = strlen( chars );
        int i, len;

        if(rndinit) {srand(time(NULL)
#ifndef WIN32 // quick windows check.
                * getpid()
#endif
                ); rndinit=0;} // seed random number generator - FIXME: we can do better ;)

        len=15+floor(rand()*16.0/(double)RAND_MAX);
        nc = (char*) xmalloc((len+1)*sizeof(char));
        for(i=0;i<len; i++) {
            nc[i] = chars[ rand() % max ];
        }
        nc[i]='\0';
        return (nc);
    }
}

#endif
